package org.imlinker.buddy;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;

import org.imlinker.list.ListItem;
import org.imlinker.list.ListModel;
import org.imlinker.message.MessageItem;
import org.imlinker.message.MessageList;
import org.imlinker.util.Images;
import org.imlinker.util.StringUtils;

import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.RosterPacket.ItemType;

@SuppressWarnings("serial")
public class BuddyList extends ListModel {

	public BuddyList(final XMPPConnection connection,
			final MessageList messageList, final ChatAdapter adapter) {
		this.roster = connection.getRoster();
		this.messageList = messageList;
		 
		chatProxy = new ChatProxy(connection, messageList, adapter);

		// 读取用户列表。
		loadBuddyList();

		// 读取最新的状态
		for (RosterEntry entry : roster.getEntries()) {
			Presence presence = roster.getPresence(entry.getUser());
			this.changeBuddyStatus(presence);
		}

		addListener(connection);
	}

	public boolean createChatWindow(String from, boolean b, String body) {
		return chatProxy.createChatWindow(from, b, body);
	}

	@Override
	public JPopupMenu getPopupMenu() {
		JPopupMenu menu = new JPopupMenu();

		java.util.ResourceBundle bundle = java.util.ResourceBundle
				.getBundle("org/imlinker/gui/Bundle"); // NOI18N
		JMenuItem item = new JMenuItem(bundle.getString("BuddyList.edit"));

		item.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				JPopupMenu temp = getList().getComponentPopupMenu();
				temp.setVisible(true);
				Point p = temp.getLocationOnScreen();
				Point q = getList().getLocationOnScreen();
				Point ans = new Point(p.x - q.x, p.y - q.y);
				temp.setVisible(false);
				int index = getList().locationToIndex(ans);

				edit(index);
			}
		});

		menu.add(item);

		return menu;
	}

	protected void edit(int index) {
		ListItem item = (ListItem) this.getElementAt(index);
		RosterEntry entry = roster.getEntry(item.getName());

		String name = entry.getName();
		String user = entry.getUser();
		if (StringUtils.isEmpty(name)) {
			name = entry.getUser();
		}

		java.util.ResourceBundle bundle = java.util.ResourceBundle
				.getBundle("org/imlinker/gui/Bundle"); // NOI18N
		String ret = JOptionPane.showInputDialog(getList(), bundle
				.getString("BuddyList.change")
				+ " " + user + bundle.getString("BuddyList.nickname"), name);

		if (StringUtils.isEmpty(ret)) {
			return;
		}

		entry.setName(ret);
		item.setTitle(ret);
		this.setElementAt(item, index);
	}

	@Override
	public void openItem(ListItem item) {
		createChatWindow(item.getName(), true, null);
	}

	private void removeBuddy(String user) {
		for (int i = 0; i < this.size(); i++) {
			ListItem item = (ListItem) this.getElementAt(i);
			if (user.startsWith(item.getName())) {
				if (item.getIcon() != Images.getUnAvailableIcon()) {
					onlines--;
				}

				this.removeElementAt(i);

				break;
			}
		}

	}

	private void addBuddy(String buddy) {
		for (int i = 0; i < this.size(); i++) {
			ListItem item = (ListItem) this.getElementAt(i);
			if (buddy.startsWith(item.getName()))
				return;
		}

		if (!roster.contains(buddy)) {
			try {
				roster.createEntry(buddy, null, null);
			} catch (XMPPException e) {
				e.printStackTrace();
			}
		}
		RosterEntry entry = roster.getEntry(buddy);

		String user = entry.getUser();
		String name = entry.getName();
		ImageIcon icon = Images.getUnAvailableIcon();

		ListItem item;
		if (StringUtils.isEmpty(name)) {
			item = new ListItem(icon, user, user);
		} else {
			item = new ListItem(icon, name, user);
		}
		this.addElement(item);

		Presence presence = roster.getPresence(buddy);
		this.changeBuddyStatus(presence);

	}

	private void changeBuddyStatus(final Presence presence) {
		// System.out.println(presence.toXML());
		if (presence.getType() == Presence.Type.unsubscribed) {
			removeBuddy(presence.getFrom());
		} else if (presence.getType() == Presence.Type.subscribed) {
			addBuddy(presence.getFrom());
		}

		String userWithResource = presence.getFrom();
		String status = presence.getStatus();

		ImageIcon icon = getIconByPresence(presence);

		for (int i = 0; i < this.size(); i++) {
			ListItem item = (ListItem) this.getElementAt(i);
			if (userWithResource.startsWith(item.getName())) {

				// 如果状态文字改变的话
				if (status != null) {
					item.setInfo(status);
				} else {
					item.setInfo("");
				}

				item.setIcon(icon);
				if (i < onlines && icon != Images.getUnAvailableIcon()) {
					this.setElementAt(item, i);

				} else {

					this.removeElement(item);
					if (icon == Images.getUnAvailableIcon()) {
						this.addElement(item);

						if (i < onlines) {
							onlines--;
						}
					} else {
						this.add(0, item);
						onlines++;
					}
				}
				break;
			}
		}
	}

	private ImageIcon getIconByPresence(final Presence presence) {

		if (presence.getType() == Presence.Type.unavailable) {
			return Images.getUnAvailableIcon();
		}

		Presence.Mode mode = presence.getMode();
		if (mode == Presence.Mode.away) {
			return Images.getAwayIcon();
		} else if (mode == Presence.Mode.dnd) {
			return Images.getDndIcon();
		} else if (mode == Presence.Mode.xa) {
			return Images.getDndIcon();
		}

		return Images.getAvailableIcon();
	}

	private void loadBuddyList() {
		ArrayList<ListItem> fullList = new ArrayList<ListItem>();  

		for (RosterEntry entry : roster.getEntries()) {
			if (entry.getType() == ItemType.none
					|| entry.getType() == ItemType.from) {
				continue;
			}

			String user = entry.getUser();
			String name = entry.getName();
			ImageIcon icon = Images.getUnAvailableIcon();

			if (name == null) {
				fullList.add(new ListItem(icon, user, user));
			} else {
				fullList.add(new ListItem(icon, name, user));
			}
		}

		this.clear();

		ListItem item;
		onlines = 0;
		for (int i = 0; i < fullList.size(); i++) {
			item = fullList.get(i);
			if (item.getIcon() != Images.getUnAvailableIcon()) {
				this.addElement(item);
				onlines++;
			}
		}

		for (int i = 0; i < fullList.size(); i++) {
			item = fullList.get(i);
			if (item.getIcon() == Images.getUnAvailableIcon()) {
				this.addElement(item);
			}
		}

	}

	private void addListener(final XMPPConnection connection) {
		connection.getRoster().addRosterListener(new RosterListener() {

			@Override
			public void entriesAdded(Collection<String> c) {
				for (String name : c) {
					addBuddy(name);
				}
			}

			@Override
			public void entriesDeleted(Collection<String> c) {
				for (String name : c) {
					removeBuddy(name);
				}
			}

			@Override
			public void entriesUpdated(Collection<String> c) {
				for (String name : c) {
					ItemType type = roster.getEntry(name).getType();
					if (type != ItemType.none && type != ItemType.from) {
						addBuddy(name);
					} else {
						removeBuddy(name);
					}
				}

			}

			@Override
			public void presenceChanged(Presence p) {
				changeBuddyStatus(p);
			}

		});

		// 监听聊天消息
		connection.addPacketListener(new PacketListener() {

			public void processPacket(Packet p) {

				Message m = (Message) p;

				if (m.getBody() != null) {
					String from = m.getFrom();
					if (from.indexOf("/") >= 0) {
						from = from.substring(0, from.indexOf("/"));
					}

					final String temp = from;
					boolean chatWindowNotCreated = createChatWindow(from,
							false, m.getBody());
					if (chatWindowNotCreated) {
						messageList.addMessage(new MessageItem("Chat from "
								+ from, "chat:" + from) {
							public void open() {
								createChatWindow(temp, true, null);
							}
						});
					}
				}
			}

		}, new MessageTypeFilter(Message.Type.chat));
	}

	private Roster roster;

	private ChatProxy chatProxy;

	private MessageList messageList;

	private int onlines = 0;
	 

}
